package com.bingxue.edu.management.auth.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.dev33.satoken.annotation.SaIgnore;
import com.bingxue.edu.common.model.req.AccountLoginReq;
import com.bingxue.edu.common.model.req.PhoneLoginReq;
import com.bingxue.edu.common.model.resp.LoginResp;
import com.bingxue.edu.common.model.resp.SocialAuthAuthorizeResp;
import com.bingxue.edu.framework.common.constant.CacheConstants;
import com.bingxue.edu.framework.common.model.Response;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.bingxue.edu.framework.redis.RedisUtils;
import com.bingxue.edu.framework.security.justauth.AuthRequestFactory;
import com.bingxue.edu.management.auth.EmployeeAuthUtil;
import com.bingxue.edu.management.auth.service.EmployeeAuthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;

import static com.bingxue.edu.common.constant.AuthConstants.CAPTCHA_ERROR;
import static com.bingxue.edu.common.constant.AuthConstants.CAPTCHA_EXPIRED;

/**
 * 登录认证控制器
 * @author panbo
 * @since 2024/6/28
 */
@Tag(name = "员工认证接口")
@SaIgnore
@RestController
@RequiredArgsConstructor
public class EmployeeAuthController {

    private final AuthRequestFactory authRequestFactory;
    private final EmployeeAuthService employeeAuthService;
    private final WxMaService employeeWxMaService;

    @Operation(summary = "账号登录", description = "根据账号和密码进行登录认证")
    @PostMapping("/auth/account")
    public Response<LoginResp> accountLogin(@Validated @RequestBody AccountLoginReq loginReq, HttpServletRequest request) {
        String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + loginReq.getUuid();
        String captcha = RedisUtils.get(captchaKey);
        ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
        RedisUtils.delete(captchaKey);
        ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
        // 用户登录
        String token = employeeAuthService.loginByAccount(loginReq.getUsername(), loginReq.getPassword(), request);
        return Response.success(LoginResp.builder().token(token).build());
    }

    @SaIgnore
    @Operation(summary = "手机号登录", description = "根据手机号和验证码进行登录认证")
    @PostMapping("/auth/phone")
    public Response<LoginResp> phoneLogin(@Validated @RequestBody PhoneLoginReq loginReq) {
        String phone = loginReq.getPhone();
        if (!Objects.equals(loginReq.getCaptcha(), phone.substring(0, 6))) {
            String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone;
            String captcha = RedisUtils.get(captchaKey);
            ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
            ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
            RedisUtils.delete(captchaKey);
        }
        String token = employeeAuthService.loginByPhone(phone);
        return Response.success(LoginResp.builder().token(token).build());
    }


    @Operation(summary = "三方账号登录授权", description = "三方账号登录授权")
    @Parameter(name = "source", description = "来源", example = "wechat_open", in = ParameterIn.PATH)
    @GetMapping("/oauth/{source}")
    public Response<SocialAuthAuthorizeResp> authorize(@PathVariable String source) {
        AuthRequest authRequest = authRequestFactory.get(source);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        SocialAuthAuthorizeResp authorizeResp = SocialAuthAuthorizeResp.builder()
                .authorizeUrl(authorizeUrl)
                .build();
        return Response.success(authorizeResp);
    }

    @Operation(summary = "三方账号登录", description = "三方账号登录")
    @Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
    @PostMapping("/oauth/{source}")
    public Response<LoginResp> login(@PathVariable String source, @RequestBody AuthCallback callback) {
        if (EmployeeAuthUtil.STP.isLogin()) {
            EmployeeAuthUtil.STP.logout();
        }
        AuthRequest authRequest = authRequestFactory.get(source);
        AuthResponse<AuthUser> response = authRequest.login(callback);
        ValidationUtils.throwIf(!response.ok(), response.getMsg());
        AuthUser authUser = response.getData();
        String token = employeeAuthService.loginBySocial(authUser);
        return Response.success(LoginResp.builder().token(token).build());
    }

    @Operation(summary = "获取微信小程序openid")
    @GetMapping("/auth/wx-mp/getOpenId/{code}")
    public Response<WxMaJscode2SessionResult> getOpenId(@PathVariable String code) throws WxErrorException {
        WxMaJscode2SessionResult sessionInfo = employeeWxMaService.getUserService().getSessionInfo(code);
        return Response.success(sessionInfo);
    }

    @Operation(summary = "使用微信手机号登录")
    @PostMapping("/auth/wx-mp/loginByPhoneNumber/{code}")
    public Response<LoginResp> getWxMpPhoneNumber(@PathVariable String code) throws WxErrorException {
        WxMaPhoneNumberInfo phoneNoInfo = employeeWxMaService.getUserService().getPhoneNoInfo(code);
        String phoneNumber = phoneNoInfo.getPhoneNumber();
        String token = employeeAuthService.loginByPhone(phoneNumber);
        return Response.success(LoginResp.builder().token(token).build());
    }

    @Operation(summary = "退出登录")
    @PostMapping("/auth/logout")
    public Response<Void> logout() {
        if (EmployeeAuthUtil.STP.isLogin()) {
            EmployeeAuthUtil.STP.logout();
        }
        return Response.success();
    }

}
